//
// Copyright (c) 2009 All Right Reserved
//
// vl
//
// 2009-01-01
// Contains ...
namespace LargoCommon.Music
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using Abstract;
using LargoCommon.Interfaces;
/// Harmonic modality.
///
/// Harmonic modality is defined by its number and appropriateness
/// to harmonic GSystem.
[Serializable]
[XmlRoot]
public sealed class HarmonicModality : BinarySchema, IHarmonic, IModalStruct
{
#region Fields
/// String of musical symbols.
private string toneSchema;
#endregion
#region Constructors
/// Initializes a new instance of the HarmonicModality class. Serializable.
public HarmonicModality() {
}
///
/// Initializes a new instance of the HarmonicModality class.
///
/// The given system.
/// Structural code.
public HarmonicModality(GeneralSystem givenSystem, string structuralCode)
: base(givenSystem, structuralCode) {
Contract.Requires(givenSystem != null);
}
///
/// Initializes a new instance of the HarmonicModality class.
///
/// The given system.
/// Bit array.
public HarmonicModality(GeneralSystem givenSystem, BitArray givenBitArray)
: base(givenSystem, givenBitArray) {
Contract.Requires(givenSystem != null);
}
///
/// Initializes a new instance of the HarmonicModality class.
///
/// The given system.
/// Number of modality.
/// Transposition shift.
public HarmonicModality(GeneralSystem givenSystem, long number, byte transposition)
: base(givenSystem, BinaryNumber.Transposition(givenSystem, number, transposition)) {
Contract.Requires(givenSystem != null);
}
///
/// Initializes a new instance of the HarmonicModality class. Serializable.
///
/// Harmonic order.
/// Melodic tones.
/// Min Altitude.
/// Properties Needed.
public HarmonicModality(byte harmonicOrder, IEnumerable melodicTones, int minAltitude, bool propertiesNeeded)
: base(HarmonicSystem.GetHarmonicSystem(harmonicOrder), (string)null) {
Contract.Requires(harmonicOrder != 0);
Contract.Requires(melodicTones != null);
//// if (melodicTones == null) { return; }
//// mt.Pitch.Element
foreach (var mt in melodicTones) {
if (mt is MusicalTone tone && tone.IsTrueTone) {
byte element = (byte)((tone.Pitch.SystemAltitude - minAltitude) % harmonicOrder);
this.On(element);
}
}
this.DetermineLevel();
if (propertiesNeeded) {
this.ComputeVariance();
this.ComputeBalance();
}
}
///
/// Initializes a new instance of the HarmonicModality class.
///
/// The given system.
/// Number of structure.
public HarmonicModality(GeneralSystem givenSystem, long number)
: base(givenSystem, number) {
}
/// Initializes a new instance of the HarmonicModality class.
/// Binary structure.
public HarmonicModality(BinaryStructure structure)
: base(structure) {
Contract.Requires(structure != null);
}
#endregion
#region Interface - simple properties
///
/// Gets or sets the name.
///
///
/// The name.
///
public string Name { get; set; }
/// Gets or sets tone representation.
/// Property description.
[XmlAttribute]
public string ToneSchema {
get => this.toneSchema ?? (this.toneSchema = this.SchemaOfTones());
set => this.toneSchema = value;
}
///
/// Gets the name and tones.
///
///
/// The name and tones.
///
public string NameAndTones => this.Name + this.ToneSchema;
///
/// Gets or sets the formal energy.
///
///
/// The formal energy.
///
public HarmonicBehavior FormalEnergy { get; set; }
/// Gets inner continuity.
/// Property description.
public float FormalContinuity => this.Properties.ContainsKey(GenProperty.InnerContinuity) ? this.Properties[GenProperty.InnerContinuity] : 0f;
/// Gets inner impulse.
/// Property description.
public float FormalImpulse => this.Properties.ContainsKey(GenProperty.InnerImpulse) ? this.Properties[GenProperty.InnerImpulse] : 0f;
/// Gets inner heterogeneity.
/// Property description.
public float Heterogeneity => this.Properties.ContainsKey(GenProperty.FormalVariance) ? this.Properties[GenProperty.FormalVariance] : 0f;
/// Gets inner balance.
/// Property description.
public float FormalBalance => this.Properties.ContainsKey(GenProperty.FormalBalance) ? this.Properties[GenProperty.FormalBalance] : 0f;
/// Gets inner balance.
/// Property description.
[XmlIgnore]
public float HarmonicModulationPower { get; private set; }
#endregion
#region Interface - object properties
/// Gets harmonic system.
/// Property description.
[XmlIgnore]
public HarmonicSystem HarmonicSystem {
get {
Contract.Ensures(Contract.Result() != null);
return (HarmonicSystem)this.GSystem;
}
}
#endregion
#region Static factory methods
///
/// Get New Harmonic Modality.
///
/// The given system.
/// Structural code.
///
/// Returns value.
///
public static HarmonicModality GetNewHarmonicModality(GeneralSystem givenSystem, string structuralCode) {
Contract.Requires(givenSystem != null);
var hm = new HarmonicModality(givenSystem, structuralCode);
hm.DetermineBehavior();
return hm;
}
///
/// Get New Harmonic Modality.
///
/// The given system.
/// Bit array.
///
/// Returns value.
///
public static HarmonicModality GetNewHarmonicModality(GeneralSystem givenSystem, BitArray bitArray) {
Contract.Requires(givenSystem != null);
var hm = new HarmonicModality(givenSystem, bitArray);
hm.DetermineBehavior();
return hm;
}
///
/// Get New Harmonic Modality.
///
/// The given system.
/// Structural Number.
/// Given Transposition.
///
/// Returns value.
///
public static HarmonicModality GetNewHarmonicModality(GeneralSystem givenSystem, long number, byte givenTransposition) {
Contract.Requires(givenSystem != null);
var hm = new HarmonicModality(givenSystem, number, givenTransposition);
hm.DetermineBehavior();
return hm;
}
///
/// Loads the harmonic modality.
///
/// The harmonic order.
/// The mod number.
/// Name of the mod.
/// Returns value.
public static HarmonicModality LoadHarmonicModality(byte harmonicOrder, long modNumber, string modName) {
var hs = HarmonicSystem.GetHarmonicSystem(harmonicOrder);
var harModality = new HarmonicModality(hs, modNumber) { Name = modName };
return harModality;
}
#endregion
#region Public methods
/// Clone object.
/// Returns value.
public override object Clone() {
var hm = GetNewHarmonicModality(this.GSystem, this.GetStructuralCode);
hm.CopyProperties(this.Properties);
return hm;
}
#endregion
#region Properties
/// Evaluate properties of the structure.
public override void DetermineBehavior() {
this.ComputeVariance();
this.ComputeBalance();
var fs = new HarmonicStateFormal((HarmonicSystem)this.GSystem, this);
this.Properties[GenProperty.InnerContinuity] = fs.FormalContinuity;
this.Properties[GenProperty.InnerImpulse] = fs.FormalImpulse;
this.Properties[GenProperty.Consonance] = fs.FormalConsonance;
}
/// Sets properties of the modality with regard to other modality.
/// Abstract modality.
public void DetermineBehaviorAfterModality(BinarySchema modality) {
if (modality == null) {
return;
}
var harmonicSystem = (HarmonicSystem)this.GSystem;
var harRelation = new HarmonicRelation(harmonicSystem, modality, this);
var continuity = harRelation.MeanValueOfProperty(GenProperty.InnerContinuity, true, true);
var impulse = harRelation.MeanValueOfProperty(GenProperty.InnerImpulse, false, true);
var power = (100.0f + impulse - continuity) / 2;
this.HarmonicModulationPower = power;
}
#endregion
#region Potential
/// Compute formal potential of given element.
/// Requested element.
/// Returns value.
public float PotentialOfElement(byte element) {
var hs = new HarmonicStateFormal((HarmonicSystem)this.GSystem, this);
hs.AddIntervalsLeadingToElement(element);
var p = hs.MeanValueOfProperty(GenProperty.FormalPotentialInfluence, false, true);
return p;
}
#endregion
#region Substructures
///
/// Harmonic substructures.
///
/// General Qualifier.
/// Upper limit.
/// Returns value.
public Collection Substructures(GeneralQualifier genQualifier, int limit) {
var hv = StructuralVarietyFactory.NewHarmonicStructModalVariety(
StructuralVarietyType.BinarySubstructuresOfModality,
this,
genQualifier,
limit);
return hv.StructList;
}
///
/// Harmonical Substructures.
///
/// Returns value.
public Collection Substructures() {
var hv = StructuralVarietyFactory.NewHarmonicStructModalVariety(
StructuralVarietyType.BinarySubstructuresOfModality,
this,
null,
10000);
return hv.StructList;
}
#endregion
#region String representation
///
/// Symbols at place.
///
/// The given place.
/// Returns value.
public string SymbolAtPlace(short givenPlace) {
var p = givenPlace;
var c = this.HarmonicSystem.Symbol(p, true);
if (!this.HarmonicSystem.IsEnharmonic(p)) {
return c;
}
var below = (byte)((p + this.Order - 1) % this.Order);
var above = (byte)((p + this.Order + 1) % this.Order);
var halftoneBelow = this.BitArray[below];
var halftoneAbove = this.BitArray[above];
if (halftoneAbove) {
return c;
}
if (halftoneBelow) {
c = this.HarmonicSystem.Symbol(p, false);
}
else {
var down2 = (byte)((p + this.Order - 2) % this.Order);
var down3 = (byte)((p + this.Order - 3) % this.Order);
var toneDown2 = this.BitArray[down2];
var toneDown3 = this.BitArray[down3];
if (toneDown2 && toneDown3) {
c = this.HarmonicSystem.Symbol(p, false);
}
}
return c;
}
///
/// Returns symbols for given level.
///
/// Given level.
///
/// Returns value.
///
public string SymbolAtLevel(short givenLevel) {
var p = this.RealPlaceAtLevel(givenLevel);
var c = this.SymbolAtPlace(p);
return c;
}
///
/// Makes tone representation of the structure.
///
///
/// Returns value.
///
public string SchemaOfTones() {
if (this.Level <= 0) {
return string.Empty;
}
var str = new StringBuilder();
var lastL = (byte)(this.Level - 1);
string s;
for (byte level = 0; level < lastL; level++) {
s = this.SymbolAtLevel(level); //// this.PlaceAtLevel
str.Append(s);
str.Append("-");
}
s = this.SymbolAtLevel(lastL); //// this.PlaceAtLevel
str.Append(s);
return str.ToString().Trim();
}
/// Writes particular formal potentials to string.
/// Returns value.
public string PotentialString() {
var s = new StringBuilder();
foreach (var e in this.Places) {
var p = this.PotentialOfElement(e);
s.AppendFormat(CultureInfo.CurrentCulture, "{0,4}: ", this.SymbolAtPlace(e));
s.AppendFormat(CultureInfo.CurrentCulture, "{0,4:F1}", p);
s.Append(Environment.NewLine);
}
return s.ToString();
}
/// String representation of the object.
/// Returns value.
public override string ToString() {
var s = new StringBuilder();
//// s.AppendLine("Harmonic modality");
//// s.AppendLine(base.ToString());
s.Append(this.ToneSchema);
//// [s appendFormat:@"%@\n",[[self potentialValues] description]];
//// [s appendFormat:@"%@\n",[[self harFunctions] description]];
return s.ToString();
}
#endregion
//// Potentials of given harmonic structure
/// Compute formal potentials of given harmonic structure.
/// Harmonic structure.
/// Returns value.
private Collection PotentialsForHarmonicStructure(BinarySchema structure) {
Contract.Requires(structure != null);
var places = structure.Places;
var arr = new Collection(); ////struct.Level
float potentialSum = 0;
foreach (var p in places.Select(this.PotentialOfElement)) {
arr.Add(p);
potentialSum = potentialSum + p;
}
#pragma warning disable 168
var i = 0;
//// ReSharper disable once UnusedVariable
foreach (var e in places.Where(e => potentialSum >= DefaultValue.AfterZero && potentialSum <= DefaultValue.LargeNumber)) {
if (i < arr.Count) {
arr[i] = arr[i] / potentialSum * 100.0f;
}
i++;
}
return arr;
}
}
}